#include "file_op.h"
// #include <openssl/sha.h>
#include <openssl/evp.h>

const char* const FILESTORAGEPATH="/home/bao/project3th/File_Storage";

int cmd_puts(char *fileName,UsrInfo_t *user,MYSQL* mysql,int netfb){
    //接口参数信息
    /* int netfb=user->netfb; */
    /* MYSQL* mysql=user->mysql; */
    //=========================================
    // char file_real_path[2048]={0};
    // strcat(file_real_path,prefix);
    // char* vitrual_path=abstract_vitrual_path(&user->virtual_path);
    // strcat(file_real_path,vitrual_path);
    // free(vitrual_path);
    // strcat(file_real_path,fileName);

    //文件固定目录
    char file_real_path[2048]={0};//改为固定的目录
    strcat(file_real_path,FILESTORAGEPATH);
    //==========================================
    char* type="FILE";
    char* recv_flag_DONE="DONE";
    char* recv_flag_PART="PART";
    train_t train;
    memset(&train,0,sizeof(train));
    off_t filesize;
    recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
    recv(netfb,&filesize,train.length,MSG_WAITALL);
    printf("filesize==%ld\n",filesize);
    bzero(train.value,sizeof(train.value));
    //========================================================
    //获得客户端的将要上传的文件的hash值
    recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
    bzero(train.value,sizeof(train.value));
    int hash_ret = recv(netfb,train.value,train.length,MSG_WAITALL);
    if(hash_ret == 0)
    {
        printf("客户端退出。\n");
        return 0;
    }
    char recv_hash[1024]={0};
    strcat(recv_hash,train.value);
    printf("recv_hash is:%s\n",recv_hash);
    //============================================================
    char file_real_hash_path[2048]={0};
    strcat(file_real_hash_path,file_real_path);
    strcat(file_real_hash_path,"/");
    strcat(file_real_hash_path,recv_hash);
    int file_fb=open(file_real_hash_path,O_RDWR|O_CREAT,0666);//打开真实文件
    // ERROR_CHECK(file_fb,-1,"open");
    if(file_fb == -1)
    {
        return -1;
    }
    bzero(&train,sizeof(train));
    //==============================================================
    //struct stat statbuf;
    //fstat(file_fb,&statbuf);
    //off_t current_filesize=statbuf.st_size;//获得当前已传的文件大小
    //========================================================
    char *suffix="_temp";
    char temp_filename[200]={0};
    strcat(temp_filename,recv_hash);//拼接hash值
    strcat(temp_filename,suffix);
    char temp_file_name_path[2048]={0};
    strcat(temp_file_name_path,file_real_path);
    strcat(temp_file_name_path,"/");
    strcat(temp_file_name_path,temp_filename);//拼接临时文件路径
    int temp_file_fd=open(temp_file_name_path,O_RDWR|O_CREAT,0666);
    // ERROR_CHECK(temp_file_fd,-1,"open temp_file");
    if(file_fb == -1)
    {
        return -1;
    }
    int temp_file_lseek_ret=lseek(temp_file_fd,0,SEEK_SET);//将临时文件的指针指向开始位置
    printf("temp_file_lseek_ret=%d\n",temp_file_lseek_ret);
    off_t size=0;
    off_t current_filesize=0;
    while(1){//每次一个off_t的大小进行读取临时文件
        int ret=read(temp_file_fd,&size,sizeof(off_t));
        if(0==ret){
            printf("read temp_file over\n");
            break;
        }
        /* off_t one_num=atol(size); */
        /* current_filesize+=one_num; */
        current_filesize+=size;
        /* bzero(size,sizeof(size)); */
    }
    send(netfb,&current_filesize,sizeof(current_filesize),MSG_NOSIGNAL);
    printf("current_filesize==%ld\n",current_filesize);
    //======================================================================
    char sql[4096]={0};
    int parent_id=-1;//被上传的文件的父id
                     //查看表有没有这个记录
                     //获取当前目录id，作为parent_id
                     //栈中存id
                     //栈中存路径字符串
    bzero(sql,sizeof(sql));
    
    //查询被传输文件的父id
    char file_path[1024] = {0};
    stack_output_path(&user->pathStack,file_path);
    snprintf(sql, sizeof(sql),
        "SELECT id FROM file_info "
        "WHERE username = '%s' "
        "AND file_path = '%s' "
        "AND type = 'DIR' "
        "AND is_del = 0",
        user->usr_name, file_path);
    
    if (mysql_query(mysql, sql)) {
        printf("查询当前目录失败: %s\n", mysql_error(mysql));
        return -1;
    }
    
    MYSQL_RES *result = mysql_store_result(mysql);
    if (!result) {//应该不会发生
        printf("dasdas\n");
        return -1;
    }
    
    MYSQL_ROW row = mysql_fetch_row(result);
    if (!row) {
        mysql_free_result(result);
        printf("错误：当前目录 '%s' 不存在或已被删除\n", file_path);
        return -1;
    }
    
    parent_id = atoi(row[0]);//得到id
    mysql_free_result(result);

    printf("sql=%s\n",sql);     //debug用

    /*int select_parent_id_ret=mysql_query(mysql,sql);
    printf("select_parent_id_ret==%d\n",select_parent_id_ret);
    MYSQL_RES* select_paren_rows=mysql_store_result(mysql);
    printf("cols=%u,rows=%lu\n",mysql_num_fields(select_paren_rows),mysql_num_rows(select_paren_rows));
    for(unsigned int i=0;i<mysql_num_rows(select_paren_rows);i++){
        MYSQL_ROW row=mysql_fetch_row(select_paren_rows);
        for(unsigned int j=0;j<mysql_num_fields(select_paren_rows);j++){
            parent_id=atoi(row[j]);
            printf("row[%d]=%s,id=%d\t",j,row[j],parent_id);
        }
        printf("\n");
    }*/
    /* mysql_free_result(select_paren_rows); */

    char virtual_file_path[1024]={0};//用于拼接包括文件的虚拟文件路径
    if(current_filesize==filesize){
        printf("该文件已存在,通知发送方不再发送，极速秒传，仅校验hash值\n");
        char flag[]="1";
        train.length=sizeof(flag);//发送标志位，让客户端不再发送
        strcpy(train.value,flag);
        send(netfb,&train.length,sizeof(train.length),0);
        send(netfb,train.value,train.length,0);
        //=================================================
        //查询表中该父目录下是否已有相同的文件记录
        bzero(sql,sizeof(sql));
        sprintf(sql,"select id from file_info where username='%s' and parent_id=%d and file_hash='%s'  and is_del=%d",
                user->usr_name,parent_id,recv_hash,0);
        printf("sql=%s\n",sql);
        int id=-1;//存储查询到的id，可能没有
        int select_ret=mysql_query(mysql,sql);
        printf("select_ret==%d\n",select_ret);
        MYSQL_RES* select_file_id_rows=mysql_store_result(mysql);
        printf("cols=%u,rows=%lu\n",mysql_num_fields(select_file_id_rows),mysql_num_rows(select_file_id_rows));
        for(unsigned int i=0;i<mysql_num_rows(select_file_id_rows);i++){
            MYSQL_ROW row=mysql_fetch_row(select_file_id_rows);
            for(unsigned int j=0;j<mysql_num_fields(select_file_id_rows);j++){
                id=atoi(row[j]);
                printf("row[%d]=%s,id=%d\t",j,row[j],id);
            }
            printf("\n");
        }
        mysql_free_result(select_file_id_rows);

        //如果表中有该文件记录
        if(id!=-1){
            //该文件记录上次没传完后的信息，则将recv_flag改为传完的标志
            bzero(sql,sizeof(sql));
            sprintf(sql,"update file_info set recv_flag='PART' where id=%d",id);
            int update_ret=mysql_query(mysql,sql);
            if(update_ret==0){
                printf("update set recv_flag=1 over\n");
            }else{
                fprintf(stderr,"%s:%s\n","insert file record",mysql_error(mysql));
            }

        }else{
            //如果表中没有这个文件记录,直接插入
            bzero(sql,sizeof(sql));
            strcat(virtual_file_path,file_path);
            int len=strlen(file_path);
            if(file_path[len-1]!='/'){
                strcat(virtual_file_path,"/");
            }
            strcat(virtual_file_path,fileName);
            sprintf(sql,"insert into file_info(filename,username,parent_id,file_path,type,file_hash,recv_flag,is_del) values('%s','%s',%d,'%s','%s','%s','%s',%d)",
                    fileName,user->usr_name,parent_id,virtual_file_path,type,recv_hash,recv_flag_DONE,0);
            printf("sql=%s\n",sql);
            int qret=mysql_query(mysql,sql);
            if(qret!=0){
                fprintf(stderr,"%s:%s\n","insert file record",mysql_error(mysql));//
            }
            printf("insert over\n");
        }
        goto sha256_Hash;//goto sha1_Hash:校验现有文件hash值
    }else if(0<=current_filesize){
        char flag[]="0";
        train.length=sizeof(flag);//发送标志位，让客户端发送
        strcpy(train.value,flag);
        send(netfb,&train.length,sizeof(train.length),0);
        send(netfb,train.value,train.length,0);
        bzero(sql,sizeof(sql));
        bzero(virtual_file_path,sizeof(virtual_file_path));
        strcat(virtual_file_path,file_path);
        if(strcmp(file_path,"/")){
            strcat(virtual_file_path,"/");
        }
        strcat(virtual_file_path,fileName);
        printf("virtual_file_path=%s\n",virtual_file_path);
        sprintf(sql,"insert into file_info(filename,username,parent_id,file_path,type,file_hash,recv_flag,is_del) values('%s','%s',%d,'%s','%s','%s','%s',%d)",
                fileName,user->usr_name,parent_id,virtual_file_path,type,recv_hash,recv_flag_PART,0);
        printf("sql=%s\n",sql);
        int qret=mysql_query(mysql,sql);
        if(qret!=0){
            fprintf(stderr,"%s:%s\n","insert file record",mysql_error(mysql));//
        }
        printf("new record insert over\n");
    }
    //========================================================================
    int lseek_ret=lseek(file_fb,current_filesize,SEEK_SET);//设置文件指向,指到文件末尾
    /* ERROR_CHECK(lseek_ret,-1,"lseek"); */
    printf("lseek_ret==%d\n",lseek_ret);
    //======================================================================
reload:
    if(filesize<100*1024*1024){
        off_t total=0;
        while(1){
            printf("%5.2lf%%\r",100.0*total/filesize);
            fflush(stdout);
            int ret = recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
            if(train.length == 0)
            {
                printf("recv over\n");
                break;
            }
            if(ret == 0)
            {
                printf("发送方中断\n");
                close(file_fb);
                close(temp_file_fd);
                return 0;
            }
            recv(netfb,train.value,train.length,MSG_WAITALL);//如果是最后的车头为0的时，接收会阻塞吗
            write(file_fb,train.value,train.length);
            off_t one_size=train.length;
            write(temp_file_fd,&one_size,sizeof(off_t));//向临时文件写入每次传入的字节数
            total+=train.length;
            // if(total==filesize){
            //     printf("recv over\n");
            //     break;
            // }
            bzero(train.value,train.length);
        }
        printf("100.00%%\n");
    }else{
        char recv_data[1024 * 1024] = {0};
        int ftruncate_add_ret = ftruncate(file_fb, filesize);
        printf("ftruncate_add_ret=%d\n", ftruncate_add_ret);

        long page_size = sysconf(_SC_PAGESIZE); // 获取系统页大小（通常 4KB）
        int slice = filesize/10000;
        off_t last_size = 0;
        while (current_filesize < filesize) {
            if (current_filesize - last_size > slice)
            {
                printf("%5.2lf%%\r", 100.0 * current_filesize / filesize);
                fflush(stdout);
                last_size = current_filesize;
            }
            off_t ret = recv(netfb, recv_data, sizeof(recv_data), 0);
            if (ret == 0) {
                printf("发送方中断\n");
                // break;
                close(temp_file_fd);
                close(file_fb);
                return 0;
            }
            // 计算对齐后的 offset（向下取整到页边界）
            off_t aligned_offset = (current_filesize / page_size) * page_size;
            // 计算映射后指针需要偏移的量（current_filesize - aligned_offset）
            size_t ptr_offset = current_filesize - aligned_offset;
            //要接收的剩余文件大小
            size_t remaining=filesize - aligned_offset;
            char *mapped = mmap(NULL, remaining, PROT_READ | PROT_WRITE, MAP_SHARED, file_fb, aligned_offset);
            if (mapped == MAP_FAILED) {
                perror("mmap");
                close(file_fb);
                close(temp_file_fd);
                return -1;
            }

            // 调整指针，使其指向接收中断位置
            char *effective_ptr = mapped + ptr_offset;
            memcpy(effective_ptr, recv_data, ret);
            /* int w_ret= */
            write(temp_file_fd,&ret,sizeof(ret));//向临时文件写入每次传入的字节数
            /* printf("ret=%ld, w_ret=%d\n",ret,w_ret); */
            // 清理映射
            munmap(mapped, remaining);
            /* current_filesize += write_length; */
            current_filesize += ret;
            /* printf("current_filesize==%ld\n",current_filesize); */
        }
        printf("接收完毕\n");
        ftruncate(file_fb, current_filesize);
    }
// sha1_Hash:
    // //判断文件是否损坏
    // //计算hash值
    // SHA_CTX ctx;
    // SHA1_Init(&ctx);
    // char buf[4096];
    // /* int fb=open(,O_RDWR); */
    // /* printf("fb==%d\n",fb); */
    // lseek(file_fb, 0, SEEK_SET);
    // while(1){
    //     bzero(buf,sizeof(buf));
    //     ssize_t ret=read(file_fb,buf,sizeof(buf));
    //     if(ret==0){
    //         printf("read over\n");
    //         break;
    //     }
    //     SHA1_Update(&ctx,buf,ret);
    // }
    // unsigned char HASH_SHA[SHA_DIGEST_LENGTH];
    // SHA1_Final(HASH_SHA,&ctx);
    // char sha1str[SHA_DIGEST_LENGTH * 2 + 1]={0};
    // printf("file hash:");
    // for(int i=0;i<sizeof(HASH_SHA);i++){
    //     char temp[3]={0};
    //     sprintf(temp,"%02x",HASH_SHA[i]);
    //     strcat(sha1str,temp);
    // }
    // printf("sha1str=%s\n",sha1str);

    // if(strcmp(sha1str,recv_hash)==0){
    //     printf("校验hash相同\n");
    //     train.length=sizeof("0");
    //     strcpy(train.value,"0");
    //     send(netfb,&train.length,sizeof(train.length),0);
    //     send(netfb,train.value,train.length,0);
    // }else{
    //     printf("校验hash不同\n");
    //     train.length=sizeof("1");
    //     strcpy(train.value,"1");
    //     send(netfb,&train.length,sizeof(train.length),0);
    //     send(netfb,train.value,train.length,0);
    //     lseek(file_fb,0,SEEK_SET);//设置文件指向,指到文件开始
    //     current_filesize=0;
    //     printf("请求重新接收文件\n");
    //     goto reload;
    // }

sha256_Hash:
    // 判断文件是否损坏
    // 计算hash值
    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
    EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
    char buf[4096];
    /* int fb=open(,O_RDWR); */
    /* printf("fb==%d\n",fb); */
    lseek(file_fb, 0, SEEK_SET);
    while (1)
    {
        bzero(buf, sizeof(buf));
        ssize_t ret = read(file_fb, buf, sizeof(buf));
        if (ret == 0)
        {
            printf("read over\n");
            break;
        }
        EVP_DigestUpdate(ctx, buf, ret);
    }
    unsigned char HASH_SHA[32];
    unsigned int encrypted_len = 0;
    EVP_DigestFinal_ex(ctx, HASH_SHA, &encrypted_len);
    char sha256str[65];
    printf("file hash:");
    for (int i = 0; i < encrypted_len; i++)
    {
        sprintf(sha256str + i * 2, "%02x", HASH_SHA[i]);
    }
    sha256str[64] = '\0';
    EVP_MD_CTX_free(ctx);
    printf("sha256str=%s\n", sha256str);

    if (strcmp(sha256str, recv_hash) == 0)
    {
        printf("校验hash相同\n");
        train.length = sizeof("0");
        strcpy(train.value, "0");
        send(netfb, &train.length, sizeof(train.length), 0);
        send(netfb, train.value, train.length, 0);
    }
    else
    {
        printf("校验hash不同\n");
        train.length = sizeof("1");
        strcpy(train.value, "1");
        send(netfb, &train.length, sizeof(train.length), MSG_NOSIGNAL);
        send(netfb, train.value, train.length, MSG_NOSIGNAL);
        // int ret1 = send(netfb, &train.length, sizeof(train.length), MSG_NOSIGNAL);
        // int ret2 = send(netfb, train.value, train.length, MSG_NOSIGNAL);
        // if(ret1 == -1 || ret2 == -1)
        // {
        //     return 0;
        // }
        lseek(file_fb, 0, SEEK_SET); // 设置文件指向,指到文件开始
        current_filesize = 0;
        printf("请求重新接收文件\n");
        goto reload;
    }

    //文件接收完毕,修改表中文件记录，将recv_flag改为1
    bzero(sql,sizeof(sql));
    sprintf(sql,"update file_info set recv_flag='%s' , is_del = 0 where parent_id=%d and filename='%s'",recv_flag_DONE,parent_id,fileName);
    int qret=mysql_query(mysql,sql);
    if(qret!=0){
        fprintf(stderr,"%s:%s\n","update file recv_flag record",mysql_error(mysql));//
    }else{
        printf("update record  set recv_flag='DONE' success\n");
        // unlink(temp_file_name_path);
    }
    close(file_fb);
    close(temp_file_fd);
    return 0;
}

// int cmd_gets(char *fileName,UsrInfo_t* user,MYSQL* mysql,int netfb){

//     //接口参数
//     /* int netfb=user->netfb; */
//     /* MYSQL* mysql=user->mysql; */
//     char username[200]={0};
//     strcat(username,user->usr_name);
//     // char file_real_hash_path[1024]={0};
//     char file_virtual_path[2048]={0};
//     //按只能下载当前用户虚拟路径的文件
//     char file_path[1024] = {0};
//     stack_output_path(&user->pathStack,file_path);
//     if (strcmp(file_path, "/") == 0) {
//         snprintf(file_virtual_path, sizeof(file_virtual_path), "/%s", fileName);
//     }else{
//         snprintf(file_virtual_path, sizeof(file_virtual_path), "%s/%s", file_path, fileName);
//     }

//     char sql[4096]={0};
//     //查找表，找到该文件记录的id
//     int file_table_id=-1;
//     snprintf(sql, sizeof(sql),
//         "SELECT id FROM file_info "
//         "WHERE username = '%s' "
//         "AND file_path = '%s' "
//         "AND type = 'FILE' "
//         "AND is_del = 0",
//         username, file_virtual_path);
//     printf("%s\n",sql);
//     if (mysql_query(mysql, sql)) {
//         printf("查询当前目录失败: %s\n", mysql_error(mysql));
//         return -1;
//     }
    
//     MYSQL_RES *result = mysql_store_result(mysql);
//     if (!result) {//应该不会发生
//         printf("dasdas\n");
//         return -1;
//     }
//     train_t train;
//     MYSQL_ROW row = mysql_fetch_row(result);
//     if (!row) {
//         mysql_free_result(result);
//         printf("错误：当前目录 '%s' 不存在或已被删除\n", file_path);
//         train.length=sizeof("0");
//         send(netfb,&train.length,sizeof(train.length),0);
//         bzero(train.value,sizeof(train.value));
//         strcat(train.value,"0");
//         send(netfb,train.value,train.length,0);
//         printf("无该文件，不可下载\n");
//         return -1;
//     }
    
//     file_table_id = atoi(row[0]);//得到id
//     mysql_free_result(result);

//   /*  bzero(sql,sizeof(sql));
//     sprintf(sql,"select id from file_info where file_path='%s' and username='%s';",file_virtual_path,username);
//     int select_file_id_qret=mysql_query(mysql,sql);
//     printf("select_file_id_qret=%d\n",select_file_id_qret);
//     int file_table_id=-1;
//     MYSQL_RES* select_file_id_rows=mysql_store_result(mysql);
//     printf("cols=%u,rows=%lu\n",mysql_num_fields(select_file_id_rows),mysql_num_rows(select_file_id_rows));
//     for(unsigned int i=0;i<mysql_num_rows(select_file_id_rows);i++){
//         MYSQL_ROW row=mysql_fetch_row(select_file_id_rows);
//         for(unsigned int j=0;j<mysql_num_fields(select_file_id_rows);j++){
//             file_table_id=atoi(row[j]);
//             printf("row[%d]=%s,id=%d\t",j,row[j],file_table_id);
//         }
//         printf("\n");
//         mysql_free_result(select_file_id_rows);
//     }*/

//     //如果表中没有这个文件记录，说明该文件没有被当前用户上传过，通知无该文件，不可下载。
//     // train_t train;

//     if(file_table_id !=-1){
//         //如果表中有这个文件记录，说明该文件被当前用户上传过，开始发送，但可能这个文件是没上传完的，也可能是空的。
//         //查找文件hash值
//        train.length=sizeof("1");
//         send(netfb,&train.length,sizeof(train.length),0);
//         bzero(train.value,sizeof(train.value));
//         strcat(train.value,"1");
//         send(netfb,train.value,train.length,0);
//         printf("存在该文件，开始传送\n");

//         char file_hash_name[1024]={0};
//         bzero(sql,sizeof(sql));
//         sprintf(sql,"select file_hash from file_info where id=%d;",file_table_id);
//         int select_file_id_qret=mysql_query(mysql,sql);
//         printf("select_file_id_qret=%d\n",select_file_id_qret);
//         MYSQL_RES* select_file_id_rows=mysql_store_result(mysql);
//         printf("cols=%u,rows=%lu\n",mysql_num_fields(select_file_id_rows),mysql_num_rows(select_file_id_rows));
//         for(unsigned int i=0;i<mysql_num_rows(select_file_id_rows);i++){
//             MYSQL_ROW row=mysql_fetch_row(select_file_id_rows);
//             for(unsigned int j=0;j<mysql_num_fields(select_file_id_rows);j++){
//                 strcat(file_hash_name,row[j]);
//                 printf("row[%d]=%s,hash_str=%s\t",j,row[j],file_hash_name);
//             }
//             printf("\n");
//         }
//         mysql_free_result(select_file_id_rows);
//         //拼接真实文件路径
//         char file_real_path[2048]={0};
//         strcat(file_real_path,FILESTORAGEPATH);
//         strcat(file_real_path,"/");
//         strcat(file_real_path,file_hash_name);
//         int file_fb=open(file_real_path,O_RDWR);
//         printf("file_fb==%d\n",file_fb);
//         /* ERROR_CHECK(file_fb,-1,"open"); */

//         struct stat statbuf;
//         fstat(file_fb,&statbuf);
//         off_t filesize=statbuf.st_size;
//         /* train.length=sizeof(filesize); */
//         /* memcpy(train.value,&filesize,sizeof(filesize)); */
//         /* send(netfb,&train.length,sizeof(train.length),MSG_NOSIGNAL); */
//         send(netfb,&filesize,sizeof(filesize),MSG_NOSIGNAL);//发文件大小
//         printf("filesize=%ld\n",filesize);
//         //send hash 字符串
//         train.length=sizeof(file_hash_name);
//         send(netfb,&train.length,sizeof(train.length),0);
//         send(netfb,file_hash_name,train.length,0);
//         //接收使用对应临时文件算出的已经传送完毕的字节数量
//         off_t current_send_over_length=-1;
//         recv(netfb,&current_send_over_length,sizeof(current_send_over_length),MSG_WAITALL);
//         printf("current_send_over_length=%ld\n",current_send_over_length);
//         //recv 接收方标识位，判断是否极速秒传
//         recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
//         bzero(train.value,sizeof(train.value));
//         recv(netfb,train.value,train.length,MSG_WAITALL);
//         //===========================================================================
//         if(strcmp(train.value,"1")==0){
//             printf("不再发送，极速秒传\n");
//             goto sha256;
//         }else{
//             printf("开始发送文件\n");
//         }
//         //==============================================================================


//         int lseek_ret=lseek(file_fb,current_send_over_length,SEEK_SET);//设置文件指向
//         printf("lseek_ret==%d\n",lseek_ret);
// re_send:
//         if(filesize<100*1024*1024){
//             while(1){//发文件内容
//                 char read_data[1024]={0};
//                 int ret=read(file_fb,read_data,sizeof(read_data));//这里不用小火车，直接全部发送
//                 if(ret==0){
//                     printf("send small file over\n");
//                     break;
//                 }
//                 send(netfb,read_data,ret,MSG_NOSIGNAL);
//             }
//         }else{
//             off_t offset = current_send_over_length;
//             off_t CHUNK_SIZE = 1024 * 1024; // 1MB，每次发送<=1MB的数据
//             long page_size = sysconf(_SC_PAGESIZE); // 获取系统页大小（通常 4KB）

//             while (offset < filesize) {
//                 size_t remaining = filesize - offset;
//                 size_t current_chunk_size = remaining < CHUNK_SIZE ? remaining : CHUNK_SIZE;

//                 // 计算对齐后的 offset（向下取整到页边界）
//                 off_t aligned_offset = (offset / page_size) * page_size;
//                 // 计算映射后指针需要偏移的量（offset - aligned_offset）,
//                 size_t ptr_offset = offset - aligned_offset;//ptr_offset > 0
//                 // 实际映射的长度 = 当前块大小 + 额外对齐偏移（避免越界）
//                 size_t mmap_length = current_chunk_size + ptr_offset;

//                 // 映射对齐后的区域
//                 char *mapped = mmap(NULL, mmap_length, PROT_READ, MAP_SHARED, file_fb, aligned_offset);
//                 if (mapped == MAP_FAILED) {
//                     perror("mmap failed");
//                     close(file_fb);
//                     return -1;
//                 }

//                 // 调整指针，使其指向文件要开始发送的位置
//                 char *effective_ptr = mapped + ptr_offset;
//                 // 实际发送的数据大小仍然是 current_chunk_size
//                 size_t sent = 0;
//                 while (sent < current_chunk_size) {
//                     ssize_t bytes_sent = send(netfb, effective_ptr + sent, current_chunk_size - sent, MSG_NOSIGNAL);
//                     if (bytes_sent == -1) {
//                         // perror("send failed");
//                         printf("客户端退出。\n");
//                         munmap(mapped, mmap_length);
//                         close(file_fb);
//                         return -2;
//                     }
//                     sent += bytes_sent;
//                 }

//                 // 清理映射
//                 munmap(mapped, mmap_length);
//                 offset += current_chunk_size;
//             }
//             printf("send big file over\n");
//             close(file_fb);
//         }
// // sha1:
// //         //recv 接收方标识位，判断是否重传
// //         recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
// //         bzero(train.value,sizeof(train.value));
// //         recv(netfb,train.value,train.length,MSG_WAITALL);
// //         if(strcmp(train.value,"1")==0){
// //             printf("文件传输错误,重新传输\n");
// //             lseek(file_fb,0,SEEK_SET);//设置指向到文件开始
// //             current_send_over_length=0;
// //             goto re_send;
// //         }else{
// //             printf("原文件无误\n");
// //         }

// sha256:
//         //recv 接收方标识位，判断是否重传
//         recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
//         bzero(train.value,sizeof(train.value));
//         recv(netfb,train.value,train.length,MSG_WAITALL);
//         if(strcmp(train.value,"1")==0){
//             printf("文件传输错误,重新传输\n");
//             lseek(file_fb,0,SEEK_SET);//设置指向到文件开始
//             current_send_over_length=0;
//             goto re_send;
//         }else{
//             printf("原文件无误\n");
//         }

//     }
//     return 0;
// }

int cmd_gets(char *fileName,UsrInfo_t* user,MYSQL* mysql,int netfb){

    //接口参数
    char username[200]={0};
    strcat(username,user->usr_name);
    char file_virtual_path[2048]={0};
    //按只能下载当前用户虚拟路径的文件
    char file_path[1024] = {0};
    stack_output_path(&user->pathStack,file_path);
    if (strcmp(file_path, "/") == 0) {
        snprintf(file_virtual_path, sizeof(file_virtual_path), "/%s", fileName);
    }else{
        snprintf(file_virtual_path, sizeof(file_virtual_path), "%s/%s", file_path, fileName);
    }

    char sql[4096]={0};
    //查找表，找到该文件记录的id
    int file_table_id=-1;
    snprintf(sql, sizeof(sql),
             "SELECT id FROM file_info "
             "WHERE username = '%s' "
             "AND file_path = '%s' "
             "AND type = 'FILE' "
             "AND is_del = 0",
             username, file_virtual_path);
    printf("%s\n",sql);
    if (mysql_query(mysql, sql)) {
        printf("查询当前目录失败: %s\n", mysql_error(mysql));
    }

    MYSQL_RES *result = mysql_store_result(mysql);
    if (!result) {//应该不会发生
        printf("dasdas\n");
    }

    MYSQL_ROW row = mysql_fetch_row(result);
    if (!row) {
        mysql_free_result(result);
        printf("错误：当前目录 '%s' 不存在或已被删除\n", file_path);
    }else{
        file_table_id = atoi(row[0]);//得到id
        mysql_free_result(result);
    }

    printf("file_table_id==%d\n",file_table_id);

    //如果表中没有这个文件记录，说明该文件没有被当前用户上传过，通知无该文件，不可下载。
    train_t train;
    printf("file_table_id=%d\n",file_table_id);
    if(file_table_id==-1){
        train.length=sizeof("0");
        send(netfb,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        bzero(train.value,sizeof(train.value));
        strcat(train.value,"0");
        send(netfb,train.value,train.length,MSG_NOSIGNAL);
        printf("无该文件，不可下载\n");
    }else{
        //如果表中有这个文件记录，说明该文件被当前用户上传过，开始发送，但可能这个文件是没上传完的，也可能是空的。
        //查找文件hash值
        train.length=sizeof("1");
        send(netfb,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        bzero(train.value,sizeof(train.value));
        strcat(train.value,"1");
        send(netfb,train.value,train.length,MSG_NOSIGNAL);
        printf("存在该文件，开始传送\n");

        char file_hash_name[1024]={0};
        bzero(sql,sizeof(sql));
        sprintf(sql,"select file_hash from file_info where id=%d;",file_table_id);
        int select_file_id_qret=mysql_query(mysql,sql);
        printf("select_file_id_qret=%d\n",select_file_id_qret);
        MYSQL_RES* select_file_id_rows=mysql_store_result(mysql);
        printf("cols=%u,rows=%lu\n",mysql_num_fields(select_file_id_rows),mysql_num_rows(select_file_id_rows));
        for(unsigned int i=0;i<mysql_num_rows(select_file_id_rows);i++){
            MYSQL_ROW row=mysql_fetch_row(select_file_id_rows);
            for(unsigned int j=0;j<mysql_num_fields(select_file_id_rows);j++){
                strcat(file_hash_name,row[j]);
                printf("row[%d]=%s,hash_str=%s\t",j,row[j],file_hash_name);
            }
            printf("\n");
        }
        mysql_free_result(select_file_id_rows);
        //拼接真实文件路径
        char file_real_path[2048]={0};
        strcat(file_real_path,FILESTORAGEPATH);
        strcat(file_real_path,"/");
        strcat(file_real_path,file_hash_name);
        int file_fb=open(file_real_path,O_RDWR);
        printf("file_fb==%d\n",file_fb);
        /* ERROR_CHECK(file_fb,-1,"open"); */

        struct stat statbuf;
        fstat(file_fb,&statbuf);
        off_t filesize=statbuf.st_size;
        send(netfb,&filesize,sizeof(filesize),MSG_NOSIGNAL);//发文件大小
        printf("filesize=%ld\n",filesize);
        //send hash 字符串
        train.length=sizeof(file_hash_name);
        send(netfb,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(netfb,file_hash_name,train.length,MSG_NOSIGNAL);
        //接收使用对应临时文件算出的已经传送完毕的字节数量
        off_t current_send_over_length=-1;
        recv(netfb,&current_send_over_length,sizeof(current_send_over_length),MSG_WAITALL);
        printf("current_send_over_length=%ld\n",current_send_over_length);
        //recv 接收方标识位，判断是否极速秒传
        recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
        bzero(train.value,sizeof(train.value));
        recv(netfb,train.value,train.length,MSG_WAITALL);
        //===========================================================================
        if(strcmp(train.value,"1")==0){
            printf("不再发送，极速秒传\n");
            goto sha256;
        }else{
            printf("开始发送文件\n");
        }
        //==============================================================================
        int lseek_ret=lseek(file_fb,current_send_over_length,SEEK_SET);//设置文件指向
        printf("lseek_ret==%d\n",lseek_ret);
re_send:
        if(filesize<100*1024*1024){
            while(1){//发文件内容
                char read_data[1024]={0};
                int ret=read(file_fb,read_data,sizeof(read_data));//这里不用小火车，直接全部发送  
                send(netfb, &ret, sizeof(ret), MSG_NOSIGNAL);
                if(ret==0){
                    printf("send small file over\n");
                    break;
                }
                send(netfb,read_data,ret,MSG_NOSIGNAL);
            }
        }else{
            off_t offset = current_send_over_length;
            off_t CHUNK_SIZE = 1024 * 1024; // 1MB，每次发送<=1MB的数据
            long page_size = sysconf(_SC_PAGESIZE); // 获取系统页大小（通常 4KB）

            while (offset < filesize) {

                size_t remaining = filesize - offset;
                size_t current_chunk_size = remaining < CHUNK_SIZE ? remaining : CHUNK_SIZE;

                // 计算对齐后的 offset（向下取整到页边界）
                off_t aligned_offset = (offset / page_size) * page_size;
                // 计算映射后指针需要偏移的量（offset - aligned_offset）,
                size_t ptr_offset = offset - aligned_offset;//ptr_offset > 0
                                                            // 实际映射的长度 = 当前块大小 + 额外对齐偏移（避免越界）
                size_t mmap_length = current_chunk_size + ptr_offset;

                // 映射对齐后的区域
                char *mapped = mmap(NULL, mmap_length, PROT_READ, MAP_SHARED, file_fb, aligned_offset);
                if (mapped == MAP_FAILED) {
                    perror("mmap failed");
                    close(file_fb);
                    return -1;
                }

                // 调整指针，使其指向文件要开始发送的位置
                char *effective_ptr = mapped + ptr_offset;
                // 实际发送的数据大小仍然是 current_chunk_size
                size_t sent = 0;
                while (sent < current_chunk_size) {
                    ssize_t bytes_sent = send(netfb, effective_ptr + sent, current_chunk_size - sent, MSG_NOSIGNAL);
                    if (bytes_sent == -1) {
                        perror("send failed");
                        /* munmap(mapped, mmap_length); */
                        /* close(file_fb); */
                        /* return -1; */
                        break;
                    }
                    sent += bytes_sent;
                }
                if(sent!=current_chunk_size){
                    break;
                }
                // 清理映射
                munmap(mapped, mmap_length);
                offset += current_chunk_size;
                /* printf("offset===%ld\n",offset); */
            }
            if(offset==filesize){
                printf("send big file over\n");
            }
            /* close(file_fb); */
        }
sha256:
        //recv 接收方标识位，判断是否重传
        recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
        bzero(train.value,sizeof(train.value));
        recv(netfb,train.value,train.length,MSG_WAITALL);
        if(strcmp(train.value,"1")==0){
            printf("文件传输错误,重新传输\n");
            lseek(file_fb,0,SEEK_SET);//设置指向到文件开始
            current_send_over_length=0;
            goto re_send;
        }else if(strcmp(train.value,"")==0){
            printf("client 中断\n");
        }
        else{
            printf("传输文件成功\n");
        }
         close(file_fb);
    }
    return 0;
}


int cmd_rm(UsrInfo_t *user,char *fileName,MYSQL *mysql,char *ret_msg,int msg_size){
    char real_path[1024] = {0};
    stack_output_path(&user->pathStack,real_path);
    char full_path[2048] = {0};
    if (strcmp(real_path, "/") == 0) {
        snprintf(full_path, sizeof(full_path), "/%s", fileName);
    } else {
        snprintf(full_path, sizeof(full_path), "%s/%s", real_path, fileName);
    }
    char query[4096] = {0};
    snprintf(query, sizeof(query),
        "SELECT id FROM file_info "
        "WHERE username = '%s' AND file_path = '%s' "
        "AND type = 'FILE' "
        "AND is_del = 0",
    user->usr_name, full_path);

    if (mysql_query(mysql, query)) {
        printf("查询语句有问题: %s\n", mysql_error(mysql));
        return -1;
    }
    //debug用
    MYSQL_RES *result = mysql_store_result(mysql);//准备MYSQL_RES
    if (!result) {
        printf("MYSQL_RES 失败！\n");//应该不会执行
        mysql_free_result(result);
        return -1;
    }
    MYSQL_ROW row = mysql_fetch_row(result);
    if (!row) {
        mysql_free_result(result);
        printf("错误：文件 '%s' 不存在或已被删除\n", full_path);
        snprintf(ret_msg,msg_size,"错误：文件 '%s' 不存在或已被删除\n", full_path);
        return -1;
    }

    int file_id = atoi(row[0]);
    mysql_free_result(result);

    snprintf(query, sizeof(query),
        "UPDATE file_info "
        "SET is_del = 1 "
        "WHERE id = %d",
        file_id);
    
    if (mysql_query(mysql, query)) {
        printf("删除文件语句失败: %s\n", mysql_error(mysql));
        return -1;
    }
    
    printf("文件 '%s' 已删除\n", full_path);
    snprintf(ret_msg,msg_size,"文件 '%s' 已删除\n", full_path);
    return 0;
}